package com.wdb007.venus.web.api.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.wdb007.venus.svc.biz.manager.ConfigInfoManager;
import com.wdb007.venus.svc.biz.utils.ExceptionUtils;
import com.wdb007.venus.svc.biz.utils.OSSUtil;
import com.wdb007.venus.svc.biz.utils.WxEncryptedDataUtil;
import com.wdb007.venus.svc.facade.AccountCashService;
import com.wdb007.venus.svc.facade.UserChargeService;
import com.wdb007.venus.svc.facade.UserService;
import com.wdb007.venus.svc.facade.account.model.AccountCashLogDTO;
import com.wdb007.venus.svc.facade.account.model.AccountCashLogVO;
import com.wdb007.venus.svc.facade.account.model.ChargeAmountVO;
import com.wdb007.venus.svc.facade.book.model.UserBorrowPageDTO;
import com.wdb007.venus.svc.facade.charge.model.CalcPayAmountDTO;
import com.wdb007.venus.svc.facade.charge.model.CalcPayAmountResultDTO;
import com.wdb007.venus.svc.facade.charge.model.ChargeAmountDTO;
import com.wdb007.venus.svc.facade.charge.model.PaymentChargeAmountDTO;
import com.wdb007.venus.svc.facade.charge.model.PaymentVIPCardDTO;
import com.wdb007.venus.svc.facade.charge.model.PaymentVIPCardResultDTO;
import com.wdb007.venus.svc.facade.charge.model.PlaceOrderReqDTO;
import com.wdb007.venus.svc.facade.charge.model.PlaceOrderRspDTO;
import com.wdb007.venus.svc.facade.charge.model.PrepareBuyBookReqDTO;
import com.wdb007.venus.svc.facade.charge.model.PrepareBuyBookResDTO;
import com.wdb007.venus.svc.facade.charge.model.QueryPayStatusDTO;
import com.wdb007.venus.svc.facade.charge.model.RefundPyStatusDTO;
import com.wdb007.venus.svc.facade.charge.model.UserRefundDTO;
import com.wdb007.venus.svc.facade.charge.model.VIPAmountDTO;
import com.wdb007.venus.svc.facade.charge.model.VIPAmountRspDTO;
import com.wdb007.venus.svc.facade.charge.model.WxUserRelationDTO;
import com.wdb007.venus.svc.facade.constant.BizConstants;
import com.wdb007.venus.svc.facade.constant.RspCodeEnum;
import com.wdb007.venus.svc.facade.exception.BizException;
import com.wdb007.venus.svc.facade.model.VenusSvcResp;
import com.wdb007.venus.svc.facade.user.model.UserAccessLogDTO;
import com.wdb007.venus.svc.facade.user.model.UserEntiretyDTO;
import com.wdb007.venus.svc.facade.user.model.UserInfoDTO;
import com.wdb007.venus.web.api.account.model.AccountCashLogModel;
import com.wdb007.venus.web.api.charge.model.AliPlaceOrderResponse;
import com.wdb007.venus.web.api.charge.model.CalcPayAmountRequest;
import com.wdb007.venus.web.api.charge.model.PaymentRequest;
import com.wdb007.venus.web.api.charge.model.PaymentVIPCardRequest;
import com.wdb007.venus.web.api.charge.model.PlaceOrderRequest;
import com.wdb007.venus.web.api.charge.model.PrepareBuyBookRequest;
import com.wdb007.venus.web.api.charge.model.WeChatPaymentResponse;
import com.wdb007.venus.web.api.charge.model.WeChatPlaceOrderResponse;
import com.wdb007.venus.web.api.charge.model.WxOpenId;
import com.wdb007.venus.web.api.charge.model.WxPaymentRequest;
import com.wdb007.venus.web.api.charge.model.WxUserRelationRequest;
import com.wdb007.venus.web.api.model.BaseResponse;
import com.wdb007.venus.web.api.model.PageQueryRequest;
import com.wdb007.venus.web.api.user.model.RegisterResponse;
import com.wdb007.venus.web.api.user.model.UserRefundRequest;
import com.wdb007.venus.web.api.user.model.UserRequest;
import com.wdb007.venus.web.api.utils.RegExpValidatorUtils;

@Controller
@RequestMapping("/charge")
public class ChargeController extends BaseController {

	private static final Logger logger = LoggerFactory.getLogger(ChargeController.class);
	
	@Autowired
	private AccountCashService accountCashService;
	
	@Autowired
	private UserChargeService userChargeService ;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private ConfigInfoManager configInfoManager;

	@RequestMapping(value="/getExpenseRecord", method=RequestMethod.GET)
	@ResponseBody
	public BaseResponse getList(PageQueryRequest request) {
		logger.info("消费记录请求参数: {}", JSON.toJSONString(request));
		BaseResponse response = success();
		
		try {
			UserBorrowPageDTO userBorrowPageDTO = new UserBorrowPageDTO();
			userBorrowPageDTO.setUserid(request.getUserid());
			userBorrowPageDTO.setPagesize(request.getPagesize());
			userBorrowPageDTO.setOffset((request.getPageno()-1)* request.getPagesize());
			AccountCashLogVO vo = accountCashService.getChargeList(userBorrowPageDTO);
			if(vo == null) {
				throw new BizException(RspCodeEnum.QUERY_LIST_IS_NULL);
			}
			response.setTotalcount(vo.getTotalcount());
			List<AccountCashLogModel> list = new ArrayList<AccountCashLogModel>(vo.getList().size());
			for(AccountCashLogDTO dto: vo.getList()) {
				AccountCashLogModel model = new AccountCashLogModel();
				model.setCharge_amount(dto.getChargeAmount());
				model.setCharge_time(dto.getChargeTime());
				model.setCharge_type(dto.getChargeType());
				model.setOper_type(dto.getOperType());
				model.setCurrency(dto.getCurrency());
				model.setBookName(dto.getBookName());
				model.setBorrowPeriod(dto.getBorrowPeriod());
				list.add(model);
			}
			response.setItems(list);
		} catch (Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("消费记录查询响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	@RequestMapping(value="/getChargeAmountList", method=RequestMethod.GET)
	@ResponseBody
	public BaseResponse getChargeAmountList(UserRequest request) {
		logger.info("充值金额列表查询请求参数: {}", JSON.toJSONString(request));
		BaseResponse response = success();
		try {
			ChargeAmountVO chargeAmountVo = null;
			boolean isDeposit = accountCashService.isDeposit(request.getUserid());
			if(isDeposit) {
				chargeAmountVo = accountCashService.getChargeOnlyAmountList();
				chargeAmountVo.setCharge_type("1");
			}else {
				chargeAmountVo = accountCashService.getChargeDepositAmountList();
				chargeAmountVo.setCharge_type("0");
			}
			response.setDetail(chargeAmountVo);
			response.setTotalcount(chargeAmountVo.getCharges().size());
		} catch (Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("充值金额列表查询响应: {}", JSON.toJSONString(response));
		return response ;
	}

	@RequestMapping(value="/getChargeAmountListV2", method=RequestMethod.GET)
	@ResponseBody
	public BaseResponse getChargeAmountListV2(UserRequest request) {
		logger.info("充值金额列表查询getChargeAmountListV2请求参数: {}", JSON.toJSONString(request));
		BaseResponse response = success();
		try {
			List<ChargeAmountDTO> list = userChargeService.getChargeAmountListV2(request.getUserid());
			response.setItems(list);
		}catch(Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("充值金额列表查询getChargeAmountListV2响应: {}", JSON.toJSONString(response));
		return response ;
	}
//	@RequestMapping(value="/getOpenid", method=RequestMethod.GET)
//	@ResponseBody
	public BaseResponse getUserinfoByWxCode(String code, String userid) {
		logger.info("获取OpenId请求参数: code:{}", code);
		BaseResponse response = success();
		try {
			checkIsNull(code, "code");
			
			Map<String, String> map = userChargeService.getOpenId(code,userid);
			WxOpenId wxOpenId = new WxOpenId();
			wxOpenId.setOpenid(map.get("openid"));
			wxOpenId.setSession_key(map.get("session_key"));
			wxOpenId.setUnionid(map.get("unionid"));
			response.setDetail(wxOpenId);
		}catch(Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("获取OpenId响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	@RequestMapping(value="/getOpenid", method=RequestMethod.GET)
	@ResponseBody
	public BaseResponse getOpenid(String code, String userid, HttpServletRequest httpRequest) {
		logger.info("获取OpenId请求参数: code:{},userid: {}", code,userid);
		if("1.3.0.0".compareTo(httpRequest.getHeader("ver")) > 0) {
			return getUserinfoByWxCode(code,userid);
		}
		BaseResponse response = success();
		try {
			checkIsNull(code, "code");
			
			UserAccessLogDTO accessLog = new UserAccessLogDTO();
			accessLog.setPartner(httpRequest.getHeader("source"));
			String ip = httpRequest.getHeader("X-Forwarded-For") ;
			if(null == ip || !RegExpValidatorUtils.isIP(ip)){
				ip = httpRequest.getRemoteAddr();
			}
			accessLog.setIp(ip);
			
			Map<String, Object> map = userChargeService.getUserinfoByWxCode(code,accessLog);
			//用户不存在
			if (ObjectUtils.isEmpty(map.get("userInfo"))) {
				response.setCode(RspCodeEnum.USER_ISNOT_UNION_WXUSER.getRspCode());
				response.setMessage(RspCodeEnum.USER_ISNOT_UNION_WXUSER.getRspMsg());
			}
			//2.用户存在,直接返回
			response.setDetail(map);
		}catch(Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("获取OpenId响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	/**
	 * 
	 * @param encryptedData 密码
	 * @param iv 
	 * @param type 1表示手机号解密
	 * @param usertoken 
	 * @param userid 如果有，判定是否需要绑定
	 * @param appid
	 * @return
	 * @throws BizException 
	 */
	@RequestMapping(value="/getAESInfo", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse getAESInfo(String usertoken, String encryptedData, String iv, String type,
			HttpServletRequest httpRequest) {
		String userid = httpRequest.getParameter("userid");
		String appid = httpRequest.getParameter("appid");
		logger.info("获取getAESInfo请求参数: token:{},encryptedData:{},iv:{},userid:{}", usertoken, encryptedData, iv, userid);
		BaseResponse response = success();
		try {
			//根据token获取sessionkey
			checkIsNull(usertoken, "usertoken");
			//如果userid存在，说明关系绑定
			if(!isEmpty(userid)) {
				WxUserRelationDTO userRelationDTO = userChargeService.getWxInfoByUserid(Long.valueOf(userid), appid);
				if(!isEmpty(userRelationDTO)) {
					usertoken = userRelationDTO.getId();
				}
			}
			
			String sessionKey = userChargeService.getSessionKey(usertoken);
			checkIsNull(sessionKey, "解密秘钥未查询到");
			
			Map<String,Object> result = new HashMap<>();
			//TODO 微信手机号自动登录解密返回
			if ("1".equals(type)) {
				// TODO 手机号返回
				Map wxUserInfo = WxEncryptedDataUtil.encryptedData(sessionKey, encryptedData, iv);
				if (!ObjectUtils.isEmpty(wxUserInfo.get("userInfo"))) {
//					String mobile = (String) JSONObject.fromObject(wxUserInfo.get("userInfo"))
//							.get("purePhoneNumber");
					String mobile = JSON.parseObject((String)wxUserInfo.get("userInfo")).getString("purePhoneNumber");
					// TODO 手机号注册
					if(!ObjectUtils.isEmpty(mobile)) {
						UserAccessLogDTO accessLog = new UserAccessLogDTO();
						accessLog.setPartner(httpRequest.getHeader("source"));
						String ip = httpRequest.getHeader("X-Forwarded-For") ;
						if(null == ip || !RegExpValidatorUtils.isIP(ip)){
							ip = httpRequest.getRemoteAddr();
						}
						accessLog.setIp(ip);
						
						try {
							String visitorId = httpRequest.getParameter("visitorId");
							VenusSvcResp<UserEntiretyDTO> resp =  userService.loginWithoutVerifaction(null, visitorId, mobile, accessLog, usertoken);
							if(resp.getRspCodeEnum() != null) {
								throw new BizException(resp.getRspCodeEnum());
							}
							if(resp.getBody().getInviteFlag() == 0) {
								response.setCode(2);
							}else if(resp.getBody().getInviteFlag() == 1) {
								response.setCode(1);
							}
							//3.注册/登录
							UserEntiretyDTO userEntiretyDTO = resp.getBody();
							RegisterResponse registerResponse = new RegisterResponse();
							BeanUtils.copyProperties(userEntiretyDTO, registerResponse);
							result.put("userInfo", registerResponse);
							result.put("moblie", mobile);
							response.setDetail(result);
						} catch (BizException e) {
							e.printStackTrace();
							// 解密失败，让用户输入手机号登录1010070016
							response.setCode(RspCodeEnum.WX_AES_ERROR.getRspCode());
							response.setMessage(RspCodeEnum.WX_AES_ERROR.getRspMsg());
							return response ;
						}
					}
					
					// TODO 返回当前手机号用户信息
				} else {
					// 解密失败，让用户输入手机号登录1010070016
					response.setCode(RspCodeEnum.WX_AES_ERROR.getRspCode());
					response.setMessage(RspCodeEnum.WX_AES_ERROR.getRspMsg());
					return response ;
				}
			}
			//群排行数据
			if("2".equals(type)) {
				Map resultInfo = WxEncryptedDataUtil.encryptedData(sessionKey, encryptedData, iv);
				response.setDetail(resultInfo);//解密返回即可
				return response;
			}
			
		}catch (Exception e) {
			// TODO: handle exception
			logger.error("处理异常", e);
			response = failed(e);

		}
		
		return response ;
	}
	
	@RequestMapping(value="/getUnionInfo", method=RequestMethod.GET)
	@ResponseBody
	public BaseResponse getUnionInfo(String unionid, HttpServletRequest httpRequest) throws BizException {
		logger.info("getUnionInfo request:[{}]",unionid);
		BaseResponse response = success();
		Map<String,Object> result = new HashMap<>();
		checkIsNull(unionid, "unionid");
		List<UserInfoDTO> dtos= userChargeService.getUserinfoByUnionid(unionid, null, null);
		String mobile = null;
		if(dtos != null && dtos.size() > 0) {
			mobile = dtos.get(0).getMobileNo();
		}
		
		if(!ObjectUtils.isEmpty(mobile)) {
			UserAccessLogDTO accessLog = new UserAccessLogDTO();
			accessLog.setPartner(httpRequest.getHeader("source"));
			String ip = httpRequest.getHeader("X-Forwarded-For") ;
			if(null == ip || !RegExpValidatorUtils.isIP(ip)){
				ip = httpRequest.getRemoteAddr();
			}
			accessLog.setIp(ip);
			
			try {
				String visitorId = httpRequest.getParameter("visitorId");
				VenusSvcResp<UserEntiretyDTO> resp =  userService.loginWithoutVerifaction(null, visitorId, mobile, accessLog, httpRequest.getParameter("unionid"));
				if(resp.getRspCodeEnum() != null) {
					throw new BizException(resp.getRspCodeEnum());
				}
				if(resp.getBody().getInviteFlag() == 0) {
					response.setCode(2);
				}else if(resp.getBody().getInviteFlag() == 1) {
					response.setCode(1);
				}
				//3.注册/登录
				UserEntiretyDTO userEntiretyDTO = resp.getBody();
				RegisterResponse registerResponse = new RegisterResponse();
				BeanUtils.copyProperties(userEntiretyDTO, registerResponse);
				result.put("userInfo", registerResponse);
				result.put("moblie", mobile);
				response.setDetail(result);
			} catch (BizException e) {
				e.printStackTrace();
			}
		}else {
			throw new BizException(RspCodeEnum.QUERY_LIST_IS_NULL);
		}
		logger.info("getUnionInfo response:[{}]",JSON.toJSON(response));
		return response ;
	}
	
	
	@RequestMapping(value="/payment", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse payment(WxPaymentRequest request,HttpServletRequest httpRequest) {
		logger.info("微信小程序payment 请求参数: {}", JSON.toJSONString(request));
		BaseResponse response = success();
		try {
			ExceptionUtils.checkIsNull(request.getChargeamount(), "chargeamount");
			ExceptionUtils.checkIsNull(request.getChargetype(), "chargetype");
			
			PlaceOrderReqDTO placeOrderReq = new PlaceOrderReqDTO();
			BeanUtils.copyProperties(request, placeOrderReq);
			String ip = httpRequest.getHeader("X-Forwarded-For") ;
			if(null == ip || !RegExpValidatorUtils.isIP(ip)){
				ip = httpRequest.getRemoteAddr();
			}
			placeOrderReq.setIp(ip);
			PlaceOrderRspDTO resp = userChargeService.payment(placeOrderReq);
			WeChatPaymentResponse paymentResponse = new WeChatPaymentResponse();
			BeanUtils.copyProperties(resp, paymentResponse);
			response.setDetail(paymentResponse);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = failed(e);
		}
		logger.info("微信小程序payment 响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	@RequestMapping(value="/placeOrder", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse placeOrder(PlaceOrderRequest request,HttpServletRequest httpRequest) {
		logger.info("request.headers.X-Forwarded-For: {}", httpRequest.getHeader("X-Forwarded-For"));
		logger.info("request.remoteAddr: {}", httpRequest.getRemoteAddr());
		logger.info("下单placeOrder请求参数: {}", JSON.toJSONString(request));
		BaseResponse response = success();
		try {
			ExceptionUtils.checkIsNull(request.getChargeamount(), "chargeamount");
			ExceptionUtils.checkIsNull(request.getChargetype(), "chargetype");
			ExceptionUtils.checkIsNull(request.getChannel(), "channel");
			PlaceOrderReqDTO placeOrderReq = new PlaceOrderReqDTO();
			BeanUtils.copyProperties(request, placeOrderReq);
			
			String ip = httpRequest.getHeader("X-Forwarded-For") ;
			if(null == ip || !RegExpValidatorUtils.isIP(ip)){
				ip = httpRequest.getRemoteAddr();
			}
			placeOrderReq.setIp(ip);
			VenusSvcResp<PlaceOrderRspDTO>  resp = userChargeService.placeOrder(placeOrderReq);
			if(null!=placeOrderReq.getChannel()&&placeOrderReq.getChannel()==0) {
				String orderStr = resp.getBody().getTrade_info();
				AliPlaceOrderResponse aliPlaceOrderResponse = new AliPlaceOrderResponse();
				aliPlaceOrderResponse.setOrderStr(orderStr);
				response.setDetail(aliPlaceOrderResponse);
			}else if(null!=placeOrderReq.getChannel()&&placeOrderReq.getChannel()==1) {
				PlaceOrderRspDTO placeOrderRspDTO = resp.getBody();
				WeChatPlaceOrderResponse chatPlaceOrderResponse = new WeChatPlaceOrderResponse();
				BeanUtils.copyProperties(placeOrderRspDTO, chatPlaceOrderResponse);
				response.setDetail(chatPlaceOrderResponse);
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = failed(e);
		}
		logger.info("下单placeOrder响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	@RequestMapping(value="/aliNotify", method=RequestMethod.POST)
	public void notify(HttpServletRequest request, HttpServletResponse response) {
		try {
			logger.info("aliNotify 回调........");
			//获取支付宝POST过来反馈信息
			Map<String,String> params = new HashMap<String,String>();
			Map requestParams = request.getParameterMap();
			for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
			    String name = (String) iter.next();
			    String[] values = (String[]) requestParams.get(name);
			    String valueStr = "";
			    for (int i = 0; i < values.length; i++) {
			        valueStr = (i == values.length - 1) ? valueStr + values[i]
			                    : valueStr + values[i] + ",";
			  	}
			    //乱码解决，这段代码在出现乱码时使用。
				//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
				params.put(name, valueStr);
			}
			boolean flag = userChargeService.rsaCheckV1(params);
			logger.info("验签成功 ? {}", flag);
			if(flag) { //验签成功
				//TODO 验签成功后
				//1.业务处理（包括校验和入库处理）
				boolean bizFlag = userChargeService.bizHandle(params);
				logger.info("业务处理成功? {}", bizFlag);
				if(bizFlag) {
					handleSuccess(response);
				}else {
					handleFailed(response);
				}
			}else {
				handleFailed(response);
			}
		} catch (Exception e) {
			logger.error("系统处理异常", e);
			handleFailed(response);
		}
	}
	/**
	 * 
	 * @Method:notifyWeChat
	 * @Description:微信支付结果通知的接收
	 * @Time 2017年8月24日 下午3:44:53
	 * @author: Tom
	 * @param request
	 * @param response
	 */
	@RequestMapping(value="/notifyWeChat", method=RequestMethod.POST)
	@ResponseBody
	public void notifyWeChat(HttpServletRequest request, HttpServletResponse response) {
		logger.info("notifyWeChat 回调........");
		StringBuffer xmlStr = new StringBuffer();
		BufferedReader reader;
		try {
			reader = request.getReader();
			String line = null;
			while ((line = reader.readLine()) != null) {
				xmlStr.append(line);
			}
			// xmlStr.
			// 初步判断返回状态码（result_code）是否为success
			Document document = DocumentHelper.parseText(xmlStr.toString());
			Element element = document.getRootElement();
			Node result_code = element.selectSingleNode("result_code");
			if (null != result_code && "SUCCESS".equals(result_code.getStringValue())) {
				// 这里注意，微信支付会返回两个订单号，out_trade_no才是商户系统内部订单号，这个才是业务处理需要的
				Node out_trade_no = element.selectSingleNode("out_trade_no");// 商户系统内部订单号
				Node time_end = element.selectSingleNode("time_end");// 支付完成时间
				Node total_fee = element.selectSingleNode("total_fee");// 支付总金额
				Node appid = element.selectSingleNode("appid");// 商户订单号
				logger.info("订单["+out_trade_no.getStringValue()+"]收到成功支付结果通知；");
				// 将微信返回的重要信息封装，然后进行统一业务处理
				Map<String, String> params = new HashMap<String, String>();
				params.put("out_trade_no", out_trade_no.getStringValue());// 商户系统内部订单号
				params.put("total_fee", total_fee.getStringValue());// 订单金额
				params.put("time_end", time_end.getStringValue());// 支付完成时间
				params.put("appid", appid.getStringValue());
				params.put("notify_info", xmlStr.toString());
				boolean bizFlag = userChargeService.weChatNotify(params);
				logger.info("业务处理成功? {}", bizFlag);
				if (bizFlag) {
					notifyWeChatResponseSuccess(response);
				} else {
					notifyWeChatResponseFail(response);
				}
			} else {// 返回信息，如非空，则为错误原因 例如：签名失败
				Node return_msg = element.selectSingleNode("return_msg");
				Node err_code = element.selectSingleNode("err_code");// 错误代码
				Node err_code_des = element.selectSingleNode("err_code_des");// 错误代码描述
				logger.error("微信统一下单支付结果返回信息错误:\t【return_msg=" + return_msg.getText() + "】err_code=【" + err_code.getStringValue()
						+ "【err_code_des" + err_code_des.getStringValue() + "】");
			}
		} catch (IOException | DocumentException e) {
			logger.error("微信支付结果通知返回的xml处理失败" , e);
		}catch(Exception e) {
			logger.error("系统处理失败" , e);
		}
	}
	@RequestMapping(value="/queryPayStatus", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse queryPayStatus(long userid) {
		BaseResponse response = success();
		logger.info("查询订单状态调用: request: {}", userid);
		try {
			QueryPayStatusDTO statusDTO =userChargeService.queryPayStatus(userid);
			response.setDetail(statusDTO);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = failed(e);
		}
		logger.info("查询订单状态响应: response: {}", JSON.toJSONString(response));
		return response;
	}
	
	@RequestMapping(value="/refundDepositByUser", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse refundDeposit(UserRequest request) {
		BaseResponse response = success();
		logger.info("退款押金调用: request: {}", JSON.toJSONString(request));
		RefundPyStatusDTO refundPyStatusDTO = null;
		try {
			refundPyStatusDTO = userChargeService.refund(request.getUserid());
			response.setDetail(refundPyStatusDTO);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = failed(e);
		}
		logger.info("退款押金响应: response: {}", JSON.toJSONString(response));
		return response;
	}
	
	@RequestMapping(value="/refundByOutTradeNo", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse refundByTradeNo(String outTradeNo) {
		BaseResponse response = success();
		logger.info("退款押金调用: refundByOutTradeNo's request: {}", outTradeNo);
		try {
			checkIsNull(outTradeNo, "outTradeNo");
			userChargeService.refund(outTradeNo);
//			response.setDetail(refundPyStatusDTO);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = failed(e);
		}
		logger.info("退款押金响应: refundByOutTradeNo's response: {}", JSON.toJSONString(response));
		return response;
	}
	/**
	 * 
	 * @Method:refundSubmitDeopsit
	 * @Description:用户退款
	 * @Time 2017年11月2日 下午3:42:25
	 * @author: Tom
	 * @param request
	 * @return
	 */
	@RequestMapping(value="/refundDeposit", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse refundSubmitDeopsit(UserRequest request) {
		BaseResponse response = success();
		logger.info("退款押金申请的请求: request: {}", JSON.toJSONString(request));
		RefundPyStatusDTO refundPyStatusDTO = null;
		try {
			refundPyStatusDTO = userChargeService.refundSubmit(request.getUserid());
			response.setDetail(refundPyStatusDTO);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = failed(e);
		}
		logger.info("退款押金申请的响应: response: {}", JSON.toJSONString(response));
		return response;
	}
	
	@RequestMapping(value="/refundDepositV2", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse refundDepositV2(UserRefundRequest request) {
		BaseResponse response = success();
		logger.info("退款押金申请refundDepositV2的请求: request: {}", JSON.toJSONString(request));
		RefundPyStatusDTO refundPyStatusDTO = null;
		try {
			UserRefundDTO userRefund = new UserRefundDTO();
			BeanUtils.copyProperties(request, userRefund);
			refundPyStatusDTO = userChargeService.refundSubmit(userRefund);
			response.setDetail(refundPyStatusDTO);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = failed(e);
		}
		
		logger.info("退款押金申请refundDepositV2的响应: response: {}", JSON.toJSONString(response));
		return response;
	}
	
	@RequestMapping(value="/refundByAdmin", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse refundByAdmin(String date) {
		BaseResponse response = success();
		logger.info("refundByAdmin~~~~~~~~~~~~~~");
		RefundPyStatusDTO refundPyStatusDTO = null;
		try {
			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			Date d = df.parse(date);
			userChargeService.exportReadyForRefund(d);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = failed(e);
		}
		logger.info("退款押金申请的响应: response: {}", JSON.toJSONString(response));
		return response;
	}
	
	
	/**
	 * 
	 * @Method:handlerXmlNoteData
	 * @Description:将返回回来的xml节点去掉<![CDATA[  ]>相关
	 * @Time 2017年8月24日 下午5:55:00
	 * @author: Tom
	 * @param xmlNoteData
	 */
	/*private String handlerXmlNoteData(String xmlNoteData) {
		return xmlNoteData.replace("<![CDATA[", "").replace("]]>", "").trim();
	}*/
	private void notifyWeChatResponseSuccess(HttpServletResponse response) {
		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/xml;charset=utf-8");  
		PrintWriter out = null;  
	    try {  
	        out = response.getWriter();  
	        out.println("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[success]]></return_msg></xml>");
	        out.flush();
	    } catch (IOException e) {  
	        e.printStackTrace();
	    } finally {  
	    }  
	}
	private void notifyWeChatResponseFail(HttpServletResponse response) {
		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/xml;charset=utf-8");  
		PrintWriter out = null;  
	    try {  
	        out = response.getWriter();  
	        out.println("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[fail]]></return_msg></xml>");
	        out.flush();
	    } catch (IOException e) {  
	        e.printStackTrace();
	    } finally {  
	    }  
	}
	private void handleFailed(HttpServletResponse response) {
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/text; charset=utf-8");  
		PrintWriter out = null;  
	    try {  
	        out = response.getWriter();  
	        out.println("failure");
	        out.flush();
	    } catch (IOException e) {  
	        e.printStackTrace();
	    } finally {  
	    }  
	}
	
	private void handleSuccess(HttpServletResponse response) {
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/text; charset=utf-8");  
		PrintWriter out = null;  
	    try {  
	        out = response.getWriter();  
	        out.println("success");  
	        out.flush();
	    } catch (IOException e) {  
	        e.printStackTrace();  
	    } finally {  
	    }  
	}
	
	
	@RequestMapping(value="/getVIPAmountList", method=RequestMethod.GET)
	@ResponseBody
	public BaseResponse getVIPAmountList(Long userid,HttpServletRequest httpRequest) {
		logger.info("获取VIP列表接口getVIPAmountList请求--userid[{}]", userid);
		BaseResponse response = success();
		try {
			VIPAmountRspDTO dto = userChargeService.getVIPAmountList(userid);
			if(ObjectUtils.isEmpty(httpRequest.getHeader("ver")) || "1.3.0.0".compareTo(httpRequest.getHeader("ver")) > 0) {
				List<VIPAmountDTO> list = dto.getList();
				
				 for(VIPAmountDTO amount : list) {
					 if("1".equals(amount.getVip_type())) {
						 amount.setVip_imgurl(configInfoManager.getImgUrlPrefix() + "/vip_imgs/vip_amount_1.png");
					 }else {
						 amount.setVip_imgurl(configInfoManager.getImgUrlPrefix() + "/vip_imgs/vip_amount_2.png");
					 }
				}
			}
			
			response.setDetail(dto);
		} catch (Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("获取VIP列表接口getVIPAmountList响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	@RequestMapping(value="/calcPayAmount", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse calcPayAmount(CalcPayAmountRequest request) {
		logger.info("计算支付金额 calcPayAmount请求--request: {}", JSON.toJSONString(request));
		BaseResponse response = success();
		try {
			checkIsNull(request.getAmount(), "amount");
			CalcPayAmountDTO calcPayAmount = new CalcPayAmountDTO();
			BeanUtils.copyProperties(request, calcPayAmount);
			CalcPayAmountResultDTO result = userChargeService.calcPayAmount(calcPayAmount);
			response.setDetail(result);
		}catch(Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("计算支付金额 calcPayAmount响应: {}", JSON.toJSONString(response));
		return response ;
			
	}
	
	@RequestMapping(value="/paymentVIPCard", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse paymentVIPCard(PaymentVIPCardRequest request, HttpServletRequest httpRequest) {
		logger.info("购买VIP下单接口 paymentVIPCard请求--request: {}", JSON.toJSONString(request));
		BaseResponse response = success();
		try {
			checkIsNull(request.getVip_type(), "vip_type");
			checkIsNull(request.getExtra_amount(), "extra_amount");
			checkIsNull(request.getPay_amount(), "pay_amount");
			PaymentVIPCardDTO vipDTO = new PaymentVIPCardDTO();
			BeanUtils.copyProperties(request, vipDTO);
			vipDTO.setUserId(request.getUserid());
			String ip = httpRequest.getHeader("X-Forwarded-For") ;
			if(null == ip || !RegExpValidatorUtils.isIP(ip)){
				ip = httpRequest.getRemoteAddr();
			}
			vipDTO.setIp(ip);
			PaymentVIPCardResultDTO result = userChargeService.paymentVIPCard(vipDTO);
			response.setDetail(result);
		}catch(Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("购买VIP下单接口 paymentVIPCard响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	
	@RequestMapping(value="/cancelPayment", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse cancelPayment(Long userid) {
		logger.info("用户取消支付接口回调 cancelPayment请求--userid: {}", userid);
		BaseResponse response = success();
		try {
			userChargeService.cancelPayment(userid);
		}catch(Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("用户取消支付接口回调 cancelPayment响应: {}", JSON.toJSONString(response));
		return response ;
	}
	@RequestMapping(value="/paymentV2", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse paymentV2(PaymentRequest request, HttpServletRequest httpRequest) {
		logger.info("余额支付下单接口 paymentV2请求--request: {}", JSON.toJSONString(request));
		BaseResponse response = success();
		try {
			checkIsNull(request.getCharge_code(), "charge_code");
			checkIsNull(request.getCharge_type(), "charge_type");
			String ip = httpRequest.getHeader("X-Forwarded-For") ;
			if(null == ip || !RegExpValidatorUtils.isIP(ip)){
				ip = httpRequest.getRemoteAddr();
			}
			if(isEmpty(request.getPay_amount())) {
				request.setPay_amount(null);
			}
			
			PaymentChargeAmountDTO pcaDTO = new PaymentChargeAmountDTO();
			BeanUtils.copyProperties(request, pcaDTO);
			pcaDTO.setIp(ip);
			PaymentVIPCardResultDTO result = userChargeService.paymentChargeAmount(pcaDTO);
			response.setDetail(result);
		}catch(Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("余额支付下单接口 paymentV2响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	@RequestMapping(value="/prepareBuyBook", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse prepareBuyBook(PrepareBuyBookRequest request) {
		logger.info("购买绘本页面 prepareBuyBook请求--request: {}", JSON.toJSONString(request));
		BaseResponse response = success();
		try {
			PrepareBuyBookReqDTO prepareBuyBookReq = new PrepareBuyBookReqDTO();
			BeanUtils.copyProperties(request, prepareBuyBookReq);
			PrepareBuyBookResDTO resDTO = userChargeService.prepareBuyBook(prepareBuyBookReq);
			response.setDetail(resDTO);;
		}catch(Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("购买绘本页面 prepareBuyBook响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	@RequestMapping(value="/saveWxUserInfo", method=RequestMethod.POST)
	@ResponseBody
	public synchronized BaseResponse saveWxUserInfo(WxUserRelationRequest request, HttpServletRequest httpRequest) {
		String useridStr = httpRequest.getParameter("userid");
		logger.info("保存用户openid等信息saveWxUserInfo请求：{}，userid:{}", JSON.toJSONString(request), httpRequest.getParameter("userid"));
		BaseResponse response = success();
		try {
			request.setAppId(httpRequest.getHeader("appId"));
			checkIsNull(request.getAppId(), "appId");
			checkIsNull(request.getUsertoken(), "usertoken");
			if(!isEmpty(useridStr)) {
				request.setUserId(Long.valueOf(useridStr));
			}
			WxUserRelationDTO relation = new WxUserRelationDTO();

			//不存在userid，则usertoken为wx_user_relation的id，直接更新
			if(isEmpty(request.getUserId())) {//用户
				BeanUtils.copyProperties(request, relation);
				relation.setId(request.getUsertoken());
				logger.info("saveWxUserInfo controller updateWxUserInfoById usertoken:{}",JSON.toJSONString(relation));
				userChargeService.updateWxUserInfoById(relation);
			}else {
				//判断token是否过期，如果过期就不保存
				String usertoken = request.getUsertoken();
				String wxtoken = userService.getTokenByChannelAndUserId(request.getUserId(), BizConstants.CHANNEL_WX);
				if(usertoken.equals(wxtoken)) {
					WxUserRelationDTO updateData = userChargeService.getWxInfoByUserid(request.getUserId(), request.getAppId());
					BeanUtils.copyProperties(request, relation);
					relation.setOpenid(updateData.getOpenid());
					if("null".equals(relation.getUnionid())) relation.setUnionid(null);
					logger.info("saveWxUserInfo controller usertoken:{}",JSON.toJSONString(relation));
					userChargeService.saveWxUserInfo(relation);
				}
			}
			
		} catch (Exception e) {
			logger.error("处理异常", e);
			response = failed(e);
		}
		logger.info("保存用户openid等信息saveWxUserInfo响应: {}", JSON.toJSONString(response));
		return response ;
	}
	
	@RequestMapping(value="/getUserinfoByUnionid", method=RequestMethod.GET)
	@ResponseBody
	public BaseResponse getUserinfoByUnionid(String unionid, String userid, String mobileNo) {
		logger.info("getUserinfoByUnionid unionid:{},userid:{},mobileNo:{}",unionid,userid,mobileNo);
		BaseResponse response = success();
		//根据unionid查找userinfo
		Long userId = null;
		if(!ObjectUtils.isEmpty(userid)) {
			userId = Long.valueOf(userid);
		}
		List<UserInfoDTO> userInfoDTOs = userChargeService.getUserinfoByUnionid(unionid,userId,mobileNo);
		response.setDetail(userInfoDTOs);
		return response;
	}
	
	@RequestMapping(value="/getOSSInfo", method=RequestMethod.POST)
	@ResponseBody
	public BaseResponse getOSSInfo(String dir,String bucket,String endpoint) {
		BaseResponse response = success();
		
		response.setDetail(OSSUtil.genOSSPostSignature(dir, bucket, endpoint));
		
		return response;
	}
	
}
